package com.klangner.math.transform;

import com.klangner.math.ast.Node;
import com.klangner.math.ast.NumericNode;
import com.klangner.math.ast.OperatorNode;
import com.klangner.math.ast.SymbolNode;


/**
 * Helper class for AddTransform
 * 
 * @author Krzysztof Langner
 *
 */
class AddTerm {

	private Node		rootNode;
	/** is this negative node? */
	private boolean		negative;
	private int 		value;
	/** Operator when OperatorNode */
	private Character	operator;
	private Node		symbolNode;
	
	/**
	 * Constructor
	 * @param node
	 */
	public AddTerm(Node node, boolean negative){
		
		rootNode = node;
		this.negative = negative;
		init();
	}
	

	/**
	 * Add 2 terms
	 * @param addTerm
	 * @return new term object or null if terms can't be added
	 */
	public AddTerm add(AddTerm term) {
		
		if(rootNode instanceof NumericNode){
			return term.add(value);
		}
		else if(rootNode instanceof SymbolNode){
			int v = negative? -1: 1;
			return term.add( v, '*', rootNode);
		}
		else if(rootNode instanceof OperatorNode &&
				(operator == '*' || operator == '/') &&
				symbolNode != null)
		{
			return term.add( value, operator, symbolNode);
		}
		
		return null;
	}
	
	
	/**
	 * @return node
	 */
	public Node getNode(){
		return rootNode;
	}

	
	/**
	 * Check if node is negative
	 * @return
	 */
	public boolean isNegative() {
		return negative;
	}


	/**
	 * convert to string
	 */
	public String toString(){
		if(rootNode == null)
			return "null";
		
		return rootNode.toString();
	}
	
	
	/**
	 * Try to add numeric value to this node
	 * @return new Term or null if can't add
	 */
	private AddTerm add(int v) {
		
		if(rootNode instanceof NumericNode){
			
			Node node = new NumericNode( Integer.toString(value+v) ); 
			return new AddTerm(node ,false); 
		}
		
		return null;
	}


	/**
	 * Try to add symbol to this node
	 * @return new Term or null if can't add
	 */
	private AddTerm add(int v, Character op, Node symbol) {
		Node node;
		
		if(rootNode instanceof SymbolNode){
			
			if(op == '*' && rootNode.isTheSame(symbol)){
				int sum = v;
				
				if(negative)
					sum --;
				else
					sum ++;
				
				node = buildNode(sum, '*', symbol);
				return new AddTerm(node ,false);
			}
		}
		else if(operator == op && symbolNode.isTheSame(symbol)){
			
			node = buildNode(value + v, op, symbol);
			return new AddTerm(node ,false);
		}
		
		return null;
	}


	/**
	 * Build operator node
	 * @param sum
	 * @param c
	 * @param symbol
	 * @return
	 */
	private Node buildNode(int sum, char c, Node symbol) {

		Node node;
		if(sum != 0){
			Node left = new NumericNode( Integer.toString(sum) ); 
			Node right = symbol;
			node = new OperatorNode("*");
			node.setFirstChild(left);
			node.setSecondChild(right);
		}
		else{
			node = new NumericNode("0");
		}
		
		return node;
	}


	/**
	 * Initialize
	 */
	private void init() {


		if(rootNode instanceof NumericNode){
			value = Integer.parseInt(rootNode.getText());
		}
		
		if(	rootNode instanceof OperatorNode &&
			(rootNode.getText().charAt(0) == '*' ||
			 rootNode.getText().charAt(0) == '/'))
		{
			operator = rootNode.getText().charAt(0);
			Node left = rootNode.getFirstChild();
			Node right = rootNode.getSecondChild();
			
			if(left instanceof NumericNode)
			{
				value = Integer.parseInt(left.getText());
				symbolNode = right;
			}
			else if(right instanceof NumericNode)
			{
				value = Integer.parseInt(right.getText());
				symbolNode = left;
			}
		}
		
		if(negative)
			value = -value;
		
	}


}
